//
// Created by korack on 25-5-19.
//
#include "NfcCard.h"

#include "Beep.h"
#include "Leds.h"
#include "Tools.h"

struct _NfcCard
{
        void          *object;
        NfcCardHandler handler;
        uint8_t        card_id[4];
        uint8_t        card_type[2];
};

static bool     is_inited = false;
static NfcCard  global_nfc_card;

static uint16_t __wait_protected_flag = 0;
#define while_with_timeout_protected(expr)           \
        __wait_protected_flag = 0;                   \
        do {                                         \
                __wait_protected_flag += 1;          \
                if (__wait_protected_flag >= 4000) { \
                        break;                       \
                }                                    \
        } while ((expr))
/////////////////////////////////////////////////////////////////////
// 功    能：读RC632寄存器
// 参数说明：Address[IN]:寄存器地址
// 返    回：读出的值
/////////////////////////////////////////////////////////////////////
unsigned char
ReadRawRC(const unsigned char Address)
{
        uint8_t data = 0;
        // Phase 1: 发送寄存器地址
        I2C_GenerateSTART(I2C2, ENABLE);
        while_with_timeout_protected(
                !I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));

        I2C_Send7bitAddress(I2C2,
                            RC522_I2C_ADDR << 1,
                            I2C_Direction_Transmitter);

        while_with_timeout_protected(
                !I2C_CheckEvent(I2C2,
                                I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

        I2C_SendData(I2C2, Address);
        while_with_timeout_protected(
                !I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

        // Phase 2: 重新启动读取数据
        I2C_GenerateSTART(I2C2, ENABLE);
        while_with_timeout_protected(
                !I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));

        I2C_Send7bitAddress(I2C2, RC522_I2C_ADDR << 1, I2C_Direction_Receiver);
        while_with_timeout_protected(
                !I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

        // 准备接收最后一个字节时发送NACK
        I2C_AcknowledgeConfig(I2C2, DISABLE);
        I2C_GenerateSTOP(I2C2, ENABLE);

        while_with_timeout_protected(
                !I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED));
        data = I2C_ReceiveData(I2C2);

        // 恢复ACK状态
        I2C_AcknowledgeConfig(I2C2, ENABLE);

        return data;
}

/////////////////////////////////////////////////////////////////////
// 功    能：写RC632寄存器
// 参数说明：Address[IN]:寄存器地址
//           value[IN]:写入的值
/////////////////////////////////////////////////////////////////////
static void
WriteRawRC(const unsigned char Address, const unsigned char value)
{
        I2C_GenerateSTART(I2C2, ENABLE);
        while_with_timeout_protected(
                !I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));

        I2C_Send7bitAddress(I2C2,
                            RC522_I2C_ADDR << 1,
                            I2C_Direction_Transmitter);
        while_with_timeout_protected(
                !I2C_CheckEvent(I2C2,
                                I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

        I2C_SendData(I2C2, Address);
        while_with_timeout_protected(
                !I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING));

        I2C_SendData(I2C2, value);
        while_with_timeout_protected(
                !I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

        I2C_GenerateSTOP(I2C2, ENABLE);
}

/////////////////////////////////////////////////////////////////////
// 功    能：清RC522寄存器位
// 参数说明：reg[IN]:寄存器地址
//           mask[IN]:清位值
/////////////////////////////////////////////////////////////////////
static void
ClearBitMask(const unsigned char reg, const unsigned char mask)
{
        char tmp = 0x0;
        tmp      = ReadRawRC(reg);
        WriteRawRC(reg, tmp & ~mask); // clear bit mask
}

/////////////////////////////////////////////////////////////////////
// 功    能：置RC522寄存器位
// 参数说明：reg[IN]:寄存器地址
//           mask[IN]:置位值
/////////////////////////////////////////////////////////////////////
void
SetBitMask(const unsigned char reg, const unsigned char mask)
{
        char tmp = 0x0;
        tmp      = ReadRawRC(reg);
        WriteRawRC(reg, tmp | mask); // set bit mask
}

#define MAXRLEN 18
/////////////////////////////////////////////////////////////////////
// 功    能：通过RC522和ISO14443卡通讯
// 参数说明：Command[IN]:RC522命令字
//           pInData[IN]:通过RC522发送到卡片的数据
//           InLenByte[IN]:发送数据的字节长度
//           pOutData[OUT]:接收到的卡片返回数据
//           *pOutLenBit[OUT]:返回数据的位长度
/////////////////////////////////////////////////////////////////////
static char
PcdComMF522(const unsigned char  Command,
            const unsigned char *pInData,
            const unsigned char  InLenByte,
            unsigned char       *pOutData,
            unsigned int        *pOutLenBit)
{
        char          status  = MI_ERR;
        unsigned char irqEn   = 0x00;
        unsigned char waitFor = 0x00;
        unsigned char n;
        unsigned int  i;
        switch (Command) {
        case PCD_AUTHENT:
                irqEn   = 0x12;
                waitFor = 0x10;
                break;
        case PCD_TRANSCEIVE:
                irqEn   = 0x77;
                waitFor = 0x30;
                break;
        default:
                break;
        }

        WriteRawRC(ComIEnReg, irqEn | 0x80);
        ClearBitMask(ComIrqReg, 0x80);
        WriteRawRC(CommandReg, PCD_IDLE);
        SetBitMask(FIFOLevelReg, 0x80);

        for (i = 0; i < InLenByte; i++)
                WriteRawRC(FIFODataReg, pInData[i]);
        WriteRawRC(CommandReg, Command);

        if (Command == PCD_TRANSCEIVE)
                SetBitMask(BitFramingReg, 0x80);

        //    i = 600;//根据时钟频率调整，操作M1卡最大等待时间25ms
        i = 2000;
        do {
                n = ReadRawRC(ComIrqReg);
                i--;
        } while (i != 0 && !(n & 0x01) && !(n & waitFor));
        ClearBitMask(BitFramingReg, 0x80);

        if (i != 0) {
                if (!(ReadRawRC(ErrorReg) & 0x1B)) {
                        status = MI_OK;
                        if (n & irqEn & 0x01)
                                status = MI_NOTAGERR;
                        if (Command == PCD_TRANSCEIVE) {
                                n = ReadRawRC(FIFOLevelReg);
                                const unsigned char lastBits =
                                        ReadRawRC(ControlReg) & 0x07;
                                if (lastBits)
                                        *pOutLenBit = (n - 1) * 8 + lastBits;
                                else
                                        *pOutLenBit = n * 8;
                                if (n == 0)
                                        n = 1;
                                if (n > MAXRLEN)
                                        n = MAXRLEN;
                                for (i = 0; i < n; i++)
                                        pOutData[i] = ReadRawRC(FIFODataReg);
                        }
                } else {
                        status = MI_ERR;
                }
        }

        SetBitMask(ControlReg, 0x80); // stop timer now
        WriteRawRC(CommandReg, PCD_IDLE);
        return status;
}

/////////////////////////////////////////////////////////////////////
// 功    能：寻卡
// 参数说明: req_code[IN]:寻卡方式
//                 0x52 = 寻感应区内所有符合14443A标准的卡
//                 0x26 = 寻未进入休眠状态的卡
//           	  pTagType[OUT]：卡片类型代码
//                 0x4400 = Mifare_UltraLight
//                 0x0400 = Mifare_One(S50)
//                 0x0200 = Mifare_One(S70)
//                 0x0800 = Mifare_Pro(X)
//                 0x4403 = Mifare_DESFire
// 返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
static char
PcdRequest(unsigned char req_code, unsigned char *pTagType)
{
        unsigned int  unLen;
        unsigned char ucComMF522Buf[MAXRLEN];
        //  unsigned char xTest ;
        ClearBitMask(Status2Reg, 0x08);
        WriteRawRC(BitFramingReg, 0x07);

        //  xTest = ReadRawRC(BitFramingReg);
        //  if(xTest == 0x07 )
        //   { LED_GREEN  =0 ;}
        // else {LED_GREEN =1 ;while(1){}}
        SetBitMask(TxControlReg, 0x03);

        ucComMF522Buf[0] = req_code;

        char status      = PcdComMF522(PCD_TRANSCEIVE,
                                  ucComMF522Buf,
                                  1,
                                  ucComMF522Buf,
                                  &unLen);
        //     if(status  == MI_OK )
        //   { LED_GREEN  =0 ;}
        //   else {LED_GREEN =1 ;}
        if (status == MI_OK && unLen == 0x10) {
                *pTagType       = ucComMF522Buf[0];
                *(pTagType + 1) = ucComMF522Buf[1];
        } else {
                status = MI_ERR;
        }

        return status;
}

/////////////////////////////////////////////////////////////////////
// 功    能：防冲撞
// 参数说明: pSnr[OUT]:卡片序列号，4字节
// 返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
static char
PcdAnticoll(unsigned char *pSnr)
{
        unsigned int  unLen;
        unsigned char ucComMF522Buf[MAXRLEN];

        ClearBitMask(Status2Reg, 0x08);
        WriteRawRC(BitFramingReg, 0x00);
        ClearBitMask(CollReg, 0x80);

        ucComMF522Buf[0] = PICC_ANTICOLL1;
        ucComMF522Buf[1] = 0x20;

        char status      = PcdComMF522(PCD_TRANSCEIVE,
                                  ucComMF522Buf,
                                  2,
                                  ucComMF522Buf,
                                  &unLen);

        if (status == MI_OK) {
                unsigned char i;
                unsigned char snr_check = 0;
                for (i = 0; i < 4; i++) {
                        *(pSnr + i) = ucComMF522Buf[i];
                        snr_check ^= ucComMF522Buf[i];
                }
                if (snr_check != ucComMF522Buf[i])
                        status = MI_ERR;
        }

        SetBitMask(CollReg, 0x80);
        return status;
}

/////////////////////////////////////////////////////////////////////
// 功    能：复位RC522
// 返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
static char
PcdReset(void)
{
        if (ReadRawRC(0x02) == 0x80)
                beep_suddenly_once(beep_new_from_global());

        WriteRawRC(CommandReg, PCD_RESETPHASE);
        WriteRawRC(ModeReg, 0x3D); // 和Mifare卡通讯，CRC初始值0x6363
        WriteRawRC(TReloadRegL, 30);
        WriteRawRC(TReloadRegH, 0);
        WriteRawRC(TModeReg, 0x8D);
        WriteRawRC(TPrescalerReg, 0x3E);
        WriteRawRC(TxAutoReg, 0x40);
        return MI_OK;
}

/////////////////////////////////////////////////////////////////////
// 开启天线
// 每次启动或关闭天险发射之间应至少有1ms的间隔
/////////////////////////////////////////////////////////////////////
static void
PcdAntennaOn()
{
        const unsigned char i = ReadRawRC(TxControlReg);
        if (!(i & 0x03))
                SetBitMask(TxControlReg, 0x03);
}

//////////////////////////////////////////////////////////////////////
// 设置RC632的工作方式
//////////////////////////////////////////////////////////////////////
static char
M500PcdConfigISOType(const unsigned char type)
{
        // ISO14443_A
        if (type == 'A') {
                ClearBitMask(Status2Reg, 0x08);

                /*     WriteRawRC(CommandReg,0x20);    //as default
                      WriteRawRC(ComIEnReg,0x80);     //as default
                      WriteRawRC(DivlEnReg,0x0);      //as default
                          WriteRawRC(ComIrqReg,0x04);     //as default
                          WriteRawRC(DivIrqReg,0x0);      //as default
                          WriteRawRC(Status2Reg,0x0);//80    //trun off
                   temperature sensor WriteRawRC(WaterLevelReg,0x08); //as
                   default WriteRawRC(ControlReg,0x20);    //as default
                          WriteRawRC(CollReg,0x80);    //as default
               */
                WriteRawRC(ModeReg, 0x3D); // 3F
                /*	   WriteRawRC(TxModeReg,0x0);      //as default???
                           WriteRawRC(RxModeReg,0x0);      //as default???
                           WriteRawRC(TxControlReg,0x80);  //as default???

                           WriteRawRC(TxSelReg,0x10);      //as default???
                   */
                WriteRawRC(RxSelReg, 0x86); // 84
                //      WriteRawRC(RxThresholdReg,0x84);//as default
                //      WriteRawRC(DemodReg,0x4D);      //as default

                //      WriteRawRC(ModWidthReg,0x13);//26
                WriteRawRC(RFCfgReg, 0x7F); // 4F
                /*   WriteRawRC(GsNReg,0x88);        //as default???
                   WriteRawRC(CWGsCfgReg,0x20);    //as default???
               WriteRawRC(ModGsCfgReg,0x20);   //as default???
        */
                // tmoLength);
                WriteRawRC(TReloadRegL, 30);
                // TReloadVal = 'h6a =tmoLength(dec)
                WriteRawRC(TReloadRegH, 0);
                WriteRawRC(TModeReg, 0x8D);
                WriteRawRC(TPrescalerReg, 0x3E);

                //     PcdSetTmo(106);
                delay_ms(10);
                PcdAntennaOn();
        } else {
                return -1;
        }

        return MI_OK;
}

NfcCard *
nfc_card_new_from_global()
{
        if (is_inited)
                return &global_nfc_card;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

        GPIO_InitTypeDef gpio = {.GPIO_Pin   = GPIO_Pin_10 | GPIO_Pin_11,
                                 .GPIO_Mode  = GPIO_Mode_AF_OD,
                                 .GPIO_Speed = GPIO_Speed_50MHz};
        GPIO_Init(GPIOB, &gpio);

        I2C_InitTypeDef i2c = {.I2C_Mode       = I2C_Mode_I2C,
                               .I2C_ClockSpeed = 100000,
                               .I2C_DutyCycle  = I2C_DutyCycle_2,
                               .I2C_Ack        = I2C_Ack_Enable,
                               .I2C_AcknowledgedAddress =
                                       I2C_AcknowledgedAddress_7bit,
                               .I2C_OwnAddress1 = 0x00};
        I2C_Init(I2C2, &i2c);
        I2C_Cmd(I2C2, ENABLE);

        global_nfc_card.handler = NULL;
        global_nfc_card.object  = NULL;
        for (int i = 0; i < 4; ++i)
                global_nfc_card.card_id[i] = 0;

        PcdReset();
        M500PcdConfigISOType('A');

        is_inited = true;
        return &global_nfc_card;
}

void
nfc_card_connect_handler(NfcCard *self, void *object, NfcCardHandler handler)
{
        self->object  = object;
        self->handler = handler;
}

void
nfc_card_test(NfcCard *self)
{
        if (PcdRequest(REQ_ALL, self->card_type) != MI_OK)
                return;

        if (PcdAnticoll(self->card_id) != MI_OK)
                return;

        if (self->handler && self->object)
                self->handler(self->object, self->card_id);
}
